<!DOCTYPE HTML>
<html lang="zh-CN">

<head>
    <!--Setting-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-siteapp">
    <meta http-equiv="Cache-Control" content="no-transform">
    <meta name="renderer" content="webkit|ie-comp|ie-stand">
    <meta name="apple-mobile-web-app-capable" content="也邢">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    <meta name="browsermode" content="application">
    <meta name="screen-orientation" content="portrait">
    <meta name="theme-version" content="1.3.0">
    <meta name="root" content="/">
    <link rel="dns-prefetch" href="https://xpfcode.gitee.io">
    <!--SEO-->

<meta name="keywords" content="java,数据结构,算法,SpringBoot,分布式,设计模式,nginx" />


<meta name="description" content="Springboot源码剖析1.环境搭建1.1 下载源码下载地址 https://github.com/spring-projects/spring-boot   下载tags为2.2.9的源码..." />


<meta name="robots" content="all" />
<meta name="google" content="all" />
<meta name="googlebot" content="all" />
<meta name="verify" content="all" />
    <!--Title-->

<title>
    
    Springboot源码剖析 |
    
    也邢
</title>


<link rel="icon" href="./img/blog.png">

    


<link rel="stylesheet" href="/css/bootstrap.min.css?rev=3.3.7.css">
<link rel="stylesheet" href="/css/font-awesome.min.css?rev=4.7.0.css">
<link rel="stylesheet" href="/css/style.css?rev=@@hash.css">

    
<div class="hide">
    <script type="text/javascript">
    var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
    document.write(unescape("%3Cspan class='cnzz_stat_icon_1263868967 hide' %3E%3Cscript%20src%3D%22https%3A%2F%2Fs95.cnzz.com%2Fz_stat.php%3Fweb_id%3D1272564536%22%3E%3C%2Fscript%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s19.cnzz.com/z_stat.php%3Fid%3D1263868967%26show%3Dpic1' type='text/javascript'%3E%3C/script%3E"));
    </script>
</div>




    

<meta name="generator" content="Hexo 5.4.1"></head>
<!--[if lte IE 8]>
<style>
    html{ font-size: 1em }
</style>
<![endif]-->
<!--[if lte IE 9]>
<div style="ie">你使用的浏览器版本过低，为了你更好的阅读体验，请更新浏览器的版本或者使用其他现代浏览器，比如Chrome、Firefox、Safari等。</div>
<![endif]-->
<body>
    <header class="main-header"  style="background-image:url(
    /./img/blog_bak.png)"
     >
    <div class="main-header-box">
        <a class="header-avatar" href="/" title='xpengfei'>
            <img src="/img/avatar.jpg" alt="logo头像" class="img-responsive center-block">
        </a>
        <div class="branding">
            <!--<h2 class="text-hide">Snippet主题,从未如此简单有趣</h2>-->
            
            <h2>
                疾风舞乱发，御马踏残阳.
            </h2>
            
        </div>
    </div>
</header>
    <nav class="main-navigation">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="navbar-header"><span class="nav-toggle-button collapsed pull-right" data-toggle="collapse" data-target="#main-menu" id="mnav">
                        <span class="sr-only"></span>
                        <i class="fa fa-bars"></i>
                    </span>
                    <a class="navbar-brand" href="https://xpfcode.gitee.io">
                        也邢</a>
                </div>
                <div class="collapse navbar-collapse" id="main-menu">
                    <ul class="menu">
                        
                        <li role="presentation" class="text-center">
                            <a href="/"><i class="fa "></i>
                                首页</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/archives/"><i class="fa "></i>
                                时间轴</a>
                        </li>
                        
                    </ul>
                </div>
            </div>
        </div>
    </div>
</nav>
    <section class="content-wrap">
        <div class="container">
            <div class="row">
                <main class="col-md-8 main-content m-post">
                    <p id="process"></p>
<article class="post">
    <div class="post-head">
        <h1 id="Springboot源码剖析">
            
            Springboot源码剖析
            
        </h1>
        <div class="post-meta">
    
    <span class="categories-meta fa-wrap">
        <i class="fa fa-folder-open-o"></i>
        
    </span>
    
    
    <span class="fa-wrap">
        <i class="fa fa-tags"></i>
        <span class="tags-meta">
            
        </span>
    </span>
    
    
    
    <span class="fa-wrap">
        <i class="fa fa-clock-o"></i>
        <span class="date-meta">
            2022/04/09</span>
    </span>
    
    
</div>
        
        
    </div>
    
    <div class="post-body post-content">
        <h2 id="Springboot源码剖析"><a href="#Springboot源码剖析" class="headerlink" title="Springboot源码剖析"></a>Springboot源码剖析</h2><h3 id="1-环境搭建"><a href="#1-环境搭建" class="headerlink" title="1.环境搭建"></a>1.环境搭建</h3><h4 id="1-1-下载源码"><a href="#1-1-下载源码" class="headerlink" title="1.1 下载源码"></a>1.1 下载源码</h4><p>下载地址 <a target="_blank" rel="noopener" href="https://github.com/spring-projects/spring-boot">https://github.com/spring-projects/spring-boot</a>   下载tags为2.2.9的源码（2.3.x之后的源码都是用的gradle管理依赖），可以直接下载对应的tar或zip压缩包，下载完成后解压</p>
<h4 id="1-2-编译源码"><a href="#1-2-编译源码" class="headerlink" title="1.2 编译源码"></a>1.2 编译源码</h4><ol>
<li><p>使用idea导入源码实现自动编译</p>
</li>
<li><p>在解压目录进入cmd，执行命令：mvn clean install  -DskipTests -Pfast   // 跳过测试用例</p>
</li>
<li><p>配置pom文件</p>
<p>项目中的pom文件里有红色警告“disable.checks”，需要在pom文件的properties属性中配置</p>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;properties&gt;</span><br><span class="line">		&lt;revision&gt;<span class="number">2.2</span><span class="number">.9</span>.RELEASE&lt;/revision&gt;</span><br><span class="line">		&lt;main.basedir&gt;$&#123;basedir&#125;&lt;/main.basedir&gt;</span><br><span class="line">		&lt;disable.checks&gt;<span class="literal">true</span>&lt;/disable.checks&gt;   <span class="comment">// 添加配置</span></span><br><span class="line">&lt;/properties&gt;</span><br></pre></td></tr></table></figure>

<h4 id="1-3-新建module"><a href="#1-3-新建module" class="headerlink" title="1.3  新建module"></a>1.3  新建module</h4><p>在源码项目中新建一个module（例：springboot-mysource），便于调试；新建的module中pom依赖的springboot版本需为2.2.9，便于调试；</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;parent&gt;</span><br><span class="line">	&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">	&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;</span><br><span class="line">	&lt;version&gt;2.2.9.RELEASE&lt;/version&gt;</span><br><span class="line">	&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;</span><br><span class="line">&lt;/parent&gt;</span><br></pre></td></tr></table></figure>

<p><img src="D:\software\Typora\Typora文件\图片\image-20210701212635917.png"></p>
<p>在此过程中如果出现报错如：Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:exec (gradle) on project spring-boot，解决方案如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;!--pom文件中做如下修改--&gt;</span><br><span class="line"></span><br><span class="line">&lt;!--第一步 设置编码格式，防止出现乱码--&gt;</span><br><span class="line">&lt;properties&gt;</span><br><span class="line">	&lt;!-- 文件拷贝时的编码 --&gt;</span><br><span class="line">	&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;</span><br><span class="line">	&lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;</span><br><span class="line">	&lt;!-- 编译时的编码 --&gt;</span><br><span class="line">    &lt;maven.compiler.encoding&gt;UTF-8&lt;/maven.compiler.encoding&gt;</span><br><span class="line">&lt;/properties&gt;</span><br><span class="line"></span><br><span class="line">&lt;!--第二步  引入plugin--&gt;</span><br><span class="line">&lt;plugin&gt;</span><br><span class="line">    &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;1.6.0&lt;/version&gt;</span><br><span class="line">    &lt;executions&gt;</span><br><span class="line">        &lt;execution&gt;</span><br><span class="line">            &lt;goals&gt;</span><br><span class="line">                &lt;goal&gt;java&lt;/goal&gt;</span><br><span class="line">            &lt;/goals&gt;</span><br><span class="line">        &lt;/execution&gt;</span><br><span class="line">    &lt;/executions&gt;</span><br><span class="line">    &lt;configuration&gt;</span><br><span class="line">    	&lt;classpathScope&gt;test&lt;/classpathScope&gt;</span><br><span class="line">    &lt;/configuration&gt;</span><br><span class="line">&lt;/plugin&gt;</span><br></pre></td></tr></table></figure>

<h4 id="1-4-验证"><a href="#1-4-验证" class="headerlink" title="1.4 验证"></a>1.4 验证</h4><p>在module：springboot-mysource 的启动类中，点击@SpringBootApplication 注解，将会跳转到本地的springboot2.2.9的源码中，至此springboot2.2.9源码环境搭建完成。</p>
<h3 id="2-依赖管理"><a href="#2-依赖管理" class="headerlink" title="2.依赖管理"></a>2.依赖管理</h3><h4 id="2-1-SpringBoot-Start"><a href="#2-1-SpringBoot-Start" class="headerlink" title="2.1 SpringBoot Start"></a>2.1 SpringBoot Start</h4><p>springboot start 对常用的依赖进行整合，将其合并到一个依赖中，这样就可以一次性添加到Maven或gradle构建中。</p>
<h4 id="2-2-spring-boot-start-parent"><a href="#2-2-spring-boot-start-parent" class="headerlink" title="2.2 spring-boot-start-parent"></a>2.2 spring-boot-start-parent</h4><p>实现springboot中涉及到的依赖的版本管理，点击spring-boot-start-parent进入spring-boot-start-parent的pom文件，文件中设置了java版本及编码格式；<img src="D:\software\Typora\Typora文件\图片\image-20210701215942677.png" alt="image-20210701215942677"></p>
<p>同时pluginManagement中进行插件管理，会设置一些插件的默认值（如：插件版本号）；</p>
<p>​    在spring-boot-start-parent的pom文件中点击spring-boot-dependencies,进入spring-boot-dependencies的pom文件，该文件中的dependencyManagement对依赖进行管理，设置的有依赖的默认值。因此，在pom文件中引入了parent后，部分依赖不需要写版本号，但是引入第三方依赖时仍需要写版本号（springboot中没有整合的第三方依赖）。</p>
<h4 id="2-3-spring-boot-start-web"><a href="#2-3-spring-boot-start-web" class="headerlink" title="2.3 spring-boot-start-web"></a>2.3 spring-boot-start-web</h4><ul>
<li>点击进入spring-boot-starter-web的pom文件，其内包含了web场景下经常要用到的所有依赖信息。包含springmvc及tomcat的相关依赖；</li>
</ul>
<h3 id="3-自动配置"><a href="#3-自动配置" class="headerlink" title="3.自动配置"></a>3.自动配置</h3><h4 id="3-1-元注解"><a href="#3-1-元注解" class="headerlink" title="3.1 元注解"></a>3.1 元注解</h4><p>元注解的作用就是负责注解其他注解，是Java提供的用于定义注解的基本注解；</p>
<table>
<thead>
<tr>
<th>元注解</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>@Retention</td>
<td>是注解类，实现声明类 Class，声明类别 Category，声明扩展 Extension；该注解用于说明自定义注解的生命周期</td>
</tr>
<tr>
<td>@Taget</td>
<td>放在自定义注解的上边，表明该注解可以使用的范围；该注解的作用是告诉 Java 将自定义的注解放在什么地方，比如类、方法、构造器、变量上等，它的值是一个枚举类型</td>
</tr>
<tr>
<td>@Inherited</td>
<td>该注解是一个标记注解，表明被标注的类型是可以被继承的。如果一个使用了 @Inherited 修饰的 Annotation 类型被用于一个Class，则这个 Annotation 将被用于该 Class 的子类</td>
</tr>
<tr>
<td>@Documented</td>
<td>表明这个注释是由 Javadoc 记录的，该注解表示是否将注解信息添加在 Java 文档中。</td>
</tr>
<tr>
<td>@intertface</td>
<td>用来自定义注释类型，该注解用来声明一个注解， 其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称，返回值类型就是参数的类型（ 返回值类型只能是基本类型、Class、String、enum ）。可以通过 default 来声明参数的默认值</td>
</tr>
</tbody></table>
<ul>
<li><p>@Retention</p>
<table>
<thead>
<tr>
<th>生命周期</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>RetentionPolicy.RUNTIME</td>
<td>始终不会丢弃， 运行期也保留读注解，可以使用反射机制读取该注解的信息。 自定义的注解通常使用这种方式。</td>
</tr>
<tr>
<td>RetentionPolicy.CLASS</td>
<td>类加载时丢弃，默认使用这种方式</td>
</tr>
<tr>
<td>RetentionPolicy.SOURCE</td>
<td>编译阶段丢弃，自定义注解在编译结束之后就不再有意义，所以它们不会写入字节码。@Overide、@SuppressWarnings 都属于这类注解。</td>
</tr>
</tbody></table>
</li>
<li><p>@Taget</p>
<table>
<thead>
<tr>
<th>属性值</th>
<th>属性值说明</th>
</tr>
</thead>
<tbody><tr>
<td>ElementType.CONSTRUCTOR</td>
<td>用于描述构造器</td>
</tr>
<tr>
<td>ElementType.FIELD</td>
<td>用于描述成员变量、对象、属性（ 包括enum实例 ）</td>
</tr>
<tr>
<td>ElementType.LOCAL_VARIABLE</td>
<td>用于描述局部变量</td>
</tr>
<tr>
<td>ElementType.METHOD</td>
<td>用于描述方法</td>
</tr>
<tr>
<td>ElementType.PACKAGE</td>
<td>用于描述包</td>
</tr>
<tr>
<td>ElementType.PARAMETER</td>
<td>用于描述参数</td>
</tr>
<tr>
<td>ElementType.TYPE</td>
<td>用于描述类、接口（ 包括注解类型 ）或 enum 声明</td>
</tr>
</tbody></table>
</li>
</ul>
<h4 id="3-2-SpringBootApplication"><a href="#3-2-SpringBootApplication" class="headerlink" title="3.2 @SpringBootApplication"></a>3.2 @SpringBootApplication</h4><p>​    该注解为组合注解，组合了@SpringBootConfiguration +@EnableAutoConfiguration+@ComponentScan 三个注解，用于标注springboot启动类（此处为自动配置过程中涉及到的内容）</p>
<ol>
<li><p>@SpringBootConfiguration   注解</p>
<ul>
<li><strong>该注解是对@Configuration 注解进行了一个包装</strong></li>
<li>@Configuration  注解是Spring内提供的一个底层注解，被该注解标注的类会被识别为配置类，同时会被组件扫描器扫描到</li>
</ul>
</li>
<li><p><strong>@Conditional</strong>  是spring4新提供的注解，它的作用是按照一定的条件进行判断，满足条件才给容器注册bean</p>
</li>
<li><p><strong>@EnableAutoConfiguration  （springboot自动配置核心注解）</strong> </p>
<p>​    <strong>Spring 中有很多以Enable开头的注解，其作用就是借助@Import来收集并注册特定场景相关的bean，并加载到IOC容器中</strong></p>
<ul>
<li>注解作用：<strong>启动自动配置功能，该注解是组合注解（@AutoConfigurationPackage + @Import(AutoConfigurationImportSelector.class)）</strong></li>
<li><strong>@AutoConfigurationPackage</strong> 注解底层借助Spring的底层注解@Import向容器中导入AutoConfigurationPackages.Registrar组件类。AutoConfigurationPackages.Registrar组件类只做了一件事，即注册一个bean（org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages）,BasePackages中有一个参数即@AutoConfigurationPackage注解所在的包路径，用于保存自动配置类供后续使用。</li>
<li>@Import(AutoConfigurationImportSelector.class)注解中**@Import** 是spring的一个底层注解，其功能是给容器导入一个组件； 这里向容器里导入的是AutoConfigurationImportSelector组件</li>
<li>AutoConfigurationImportSelector组件：该组件可以帮助springboot应用将所有符合条件的@Configuration配置都加载到当前springboot创建并使用的IOC容器（ApplicationContext）中</li>
</ul>
</li>
<li><p>@ComponentScan  注解</p>
<ol>
<li><p>作用：从定义的扫描路径中，找出标识了需要装配的类，自动装配到spring的bean容器中</p>
</li>
<li><p>常用属性如下：</p>
<ol>
<li>basePackages、value：指定扫描路径，如果为空则以@ComponentScan注解标注的类所在的包为基本的扫描路径</li>
<li>basePackageClasses：指定具体扫描的类</li>
<li>includeFilters：指定满足filter条件的类</li>
<li>excludeFilters：指定排除filter条件的类</li>
</ol>
</li>
<li><p>includeFilters及excludeFilters的FilterType可选：ANNOTATION=注解类型 默认，ASSIGNABLE_TYPE（指定固定类）、ASPECTJ（ASPECTJ类型）、REGEX（正则表达式）、CUSTOM（自定义类型），自定义的Filter接口需要实现TypeFilter接口</p>
</li>
<li><p>@ComponentScan配置如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 注解扫描</span></span><br><span class="line"><span class="meta">@ComponentScan(excludeFilters = &#123; @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),</span></span><br><span class="line"><span class="meta">		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) &#125;)</span>	</span><br></pre></td></tr></table></figure>

<p>借助excludeFilters将FilterType、TypeExcludeFilter这两个类进行排除。</p>
<p>当前@ComponentScan注解没有标注basePackage及value，所以扫描默认路径为@ComponentScan注解类所在的包为基本的扫描路径（即@SpringBootApplication注解的项目启动类所在的包）</p>
</li>
</ol>
</li>
</ol>
<h4 id="3-3-自动配置原理总结"><a href="#3-3-自动配置原理总结" class="headerlink" title="3.3 自动配置原理总结"></a>3.3 自动配置原理总结</h4><ol>
<li>从spring.factories配置文件中加载自动配置类信息（包含自动配置类的全路径）</li>
<li>在加载到的自动配置类集合中排除掉@EnableAutoConfiguration注解的exclude属性指定的自动配置类</li>
<li>使用AutoConfigurationImportFilter接口过滤自动配置类，判断是否符合其标注注解（有标注时判断）@ConditionalOnClass、@ConditionalOnBean及@ConditionalOnWebApplication的条件，若符合则返回匹配结果</li>
<li>触发AutoiConfigurationImportEvent事件，通知ConditionEvaluationReport条件评估报告器，分别记录符合条件的自动配置类以及exclude需要排除的自动配置类信息</li>
<li>再将需要exclude排除的自动配置类，从符合条件的自动配置类集合中移除，并对标注有@Order注解的自动配置类进行排序，完成最终过滤</li>
<li>spring将最后过滤筛选排序后的自动配置类导入IOC容器中<img src="D:\software\Typora\Typora文件\图片\image-20210703203725089.png" alt="image-20210703203725089"></li>
</ol>
<h3 id="4-run方法执行流程"><a href="#4-run方法执行流程" class="headerlink" title="4.run方法执行流程"></a>4.run方法执行流程</h3><h4 id="4-1-SpringBootApplication-初始化过程"><a href="#4-1-SpringBootApplication-初始化过程" class="headerlink" title="4.1 SpringBootApplication  初始化过程"></a>4.1 SpringBootApplication  初始化过程</h4><ol>
<li>推断应用类型，会根据应用类型初始化对应的环境，常用的一般都是servlet环境</li>
<li>初始化classpath下META-INF/spring.properties 中已经配置的ApplicationContextInitializer 初始化器</li>
<li>初始化classpath下META-INF/spring.properties 中已经配置的ApplicationListener 监听器</li>
<li>根据调用栈，推断出main方法的类名</li>
</ol>
<p>SpringBootApplication初始化代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 启动类中的main方法</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">       <span class="comment">// ① 点击run方法</span></span><br><span class="line">	SpringApplication.run(SpringBootMySourceApplication.class, args);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ② </span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ConfigurableApplicationContext <span class="title function_">run</span><span class="params">(Class&lt;?&gt; primarySource, String... args)</span> &#123;</span><br><span class="line">	<span class="comment">// 调用重载方法</span></span><br><span class="line">	<span class="keyword">return</span> run(<span class="keyword">new</span> <span class="title class_">Class</span>&lt;?&gt;[]&#123;primarySource&#125;, args);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ③ </span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ConfigurableApplicationContext <span class="title function_">run</span><span class="params">(Class&lt;?&gt;[] primarySources, String[] args)</span> &#123;</span><br><span class="line">	<span class="comment">// 初始化SpringApplication并执行run方法</span></span><br><span class="line">	<span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">SpringApplication</span>(primarySources).run(args);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ④</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">SpringApplication</span><span class="params">(Class&lt;?&gt;... primarySources)</span> &#123;</span><br><span class="line">	<span class="comment">// 调用重载</span></span><br><span class="line">	<span class="built_in">this</span>(<span class="literal">null</span>, primarySources);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Create a new &#123;<span class="doctag">@link</span> SpringApplication&#125; instance. The application context will load</span></span><br><span class="line"><span class="comment"> * beans from the specified primary sources (see &#123;<span class="doctag">@link</span> SpringApplication class-level&#125;</span></span><br><span class="line"><span class="comment"> * documentation for details. The instance can be customized before calling</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> #run(String...)&#125;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> resourceLoader the resource loader to use</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> primarySources the primary bean sources</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> #run(Class, String[])</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> #setSources(Set)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// ⑤ SpringBootApplication初始化方法</span></span><br><span class="line"><span class="meta">@SuppressWarnings(&#123;&quot;unchecked&quot;, &quot;rawtypes&quot;&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">SpringApplication</span><span class="params">(ResourceLoader resourceLoader, Class&lt;?&gt;... primarySources)</span> &#123;</span><br><span class="line">	<span class="comment">// 设置资源加载器为null</span></span><br><span class="line">	<span class="built_in">this</span>.resourceLoader = resourceLoader;</span><br><span class="line">	<span class="comment">// 断言 资源加载类 primarySources 不能为空</span></span><br><span class="line">	Assert.notNull(primarySources, <span class="string">&quot;PrimarySources must not be null&quot;</span>);</span><br><span class="line">	<span class="comment">// 将primarySources 数组转化为List并存入LinkedHashSet集合中</span></span><br><span class="line">	<span class="built_in">this</span>.primarySources = <span class="keyword">new</span> <span class="title class_">LinkedHashSet</span>&lt;&gt;(Arrays.asList(primarySources));</span><br><span class="line">	<span class="comment">// 1.1 推断应用类型，后面根据应用类型初始化对应的环境。常用的一般都是servlet环境</span></span><br><span class="line">	<span class="built_in">this</span>.webApplicationType = WebApplicationType.deduceFromClasspath();</span><br><span class="line">	<span class="comment">// 1.2 初始化classpath下 META-INF/spring.properties中已经配置的ApplicationContextInitializer 初始化器</span></span><br><span class="line">	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));</span><br><span class="line">	<span class="comment">// 1.3 初始化classpath下所有已配置的 ApplicationListener 监听器</span></span><br><span class="line">	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));</span><br><span class="line">	<span class="comment">// 1.4 根据调用栈，推断出 main方法的类名</span></span><br><span class="line">	<span class="built_in">this</span>.mainApplicationClass = deduceMainApplicationClass();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="4-2-run方法执行流程"><a href="#4-2-run方法执行流程" class="headerlink" title="4.2 run方法执行流程"></a>4.2 run方法执行流程</h4><p>run方法实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">	 * Run the Spring application, creating and refreshing a new</span></span><br><span class="line"><span class="comment">	 * &#123;<span class="doctag">@link</span> ApplicationContext&#125;.</span></span><br><span class="line"><span class="comment">	 *</span></span><br><span class="line"><span class="comment">	 * <span class="doctag">@param</span> args the application arguments (usually passed from a Java main method)</span></span><br><span class="line"><span class="comment">	 * <span class="doctag">@return</span> a running &#123;<span class="doctag">@link</span> ApplicationContext&#125;</span></span><br><span class="line"><span class="comment">	 * &lt;p&gt;</span></span><br><span class="line"><span class="comment">	 * 运行spring应用，并刷新一个新的ApplicationContext（Spring的上下文），ConfigurableApplicationContext是ApplicationContext接口的子接口。</span></span><br><span class="line"><span class="comment">	 * 在ApplicationContext的基础上增加了配置上下文的工具，ConfigurableApplicationContext是容器的高级接口。</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">public</span> ConfigurableApplicationContext <span class="title function_">run</span><span class="params">(String... args)</span> &#123;</span><br><span class="line">		<span class="comment">// 记录程序运行时间</span></span><br><span class="line">		<span class="type">StopWatch</span> <span class="variable">stopWatch</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StopWatch</span>();</span><br><span class="line">		stopWatch.start();</span><br><span class="line">		<span class="comment">// ConfigurableApplicationContext ---spring的上下文</span></span><br><span class="line">		<span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">		Collection&lt;SpringBootExceptionReporter&gt; exceptionReporters = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">		configureHeadlessProperty();</span><br><span class="line">		<span class="comment">// 1. 获取并启动监听器</span></span><br><span class="line">		<span class="type">SpringApplicationRunListeners</span> <span class="variable">listeners</span> <span class="operator">=</span> getRunListeners(args);</span><br><span class="line">		listeners.starting();</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			<span class="type">ApplicationArguments</span> <span class="variable">applicationArguments</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultApplicationArguments</span>(args);</span><br><span class="line">			<span class="comment">// 2. 构造应用上下文环境</span></span><br><span class="line">			<span class="type">ConfigurableEnvironment</span> <span class="variable">environment</span> <span class="operator">=</span> prepareEnvironment(listeners, applicationArguments);</span><br><span class="line">			<span class="comment">// 处理要忽略的bean</span></span><br><span class="line">			configureIgnoreBeanInfo(environment);</span><br><span class="line">			<span class="comment">// 打印banner</span></span><br><span class="line">			<span class="type">Banner</span> <span class="variable">printedBanner</span> <span class="operator">=</span> printBanner(environment);</span><br><span class="line">			<span class="comment">// 3. 初始化应用上下文</span></span><br><span class="line">			context = createApplicationContext();</span><br><span class="line">			<span class="comment">// 实例化SpringBootExceptionReporter.class，用来支持报告启动时的报错</span></span><br><span class="line">			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,</span><br><span class="line">					<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;ConfigurableApplicationContext.class&#125;, context);</span><br><span class="line">			<span class="comment">// 4. 刷新应用上下文前的准备阶段</span></span><br><span class="line">			prepareContext(context, environment, listeners, applicationArguments, printedBanner);</span><br><span class="line">			<span class="comment">// 5. 刷新应用上下文</span></span><br><span class="line">			refreshContext(context);</span><br><span class="line">			<span class="comment">// 6. 刷新应用上下文后的扩展接口</span></span><br><span class="line">			afterRefresh(context, applicationArguments);</span><br><span class="line">			<span class="comment">// 事件记录停止</span></span><br><span class="line">			stopWatch.stop();</span><br><span class="line">			<span class="keyword">if</span> (<span class="built_in">this</span>.logStartupInfo) &#123;</span><br><span class="line">				<span class="keyword">new</span> <span class="title class_">StartupInfoLogger</span>(<span class="built_in">this</span>.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);</span><br><span class="line">			&#125;</span><br><span class="line">			listeners.started(context);</span><br><span class="line">			callRunners(context, applicationArguments);</span><br><span class="line">		&#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">			handleRunFailure(context, ex, exceptionReporters, listeners);</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(ex);</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			listeners.running(context);</span><br><span class="line">		&#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">			handleRunFailure(context, ex, exceptionReporters, <span class="literal">null</span>);</span><br><span class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(ex);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> context;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h5 id="4-2-1-获取启动监听器"><a href="#4-2-1-获取启动监听器" class="headerlink" title="4.2.1 获取启动监听器"></a>4.2.1 获取启动监听器</h5><ol>
<li><p>在classpath下META-INF/spring.properties中获取key为“org.springframework.boot.SpringApplicationRunListener”的监听器，即是：org.springframework.boot.context.event.EventPublishingRunListener</p>
</li>
<li><p>通过 listeners.starting(); 启动监听器</p>
</li>
<li><p>SpringApplicationRunListener  监听器的作用是：负责在springboot启动的不同阶段，广播出不同的消息，传递给ApplicationListener监听器实现类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 相关代码：</span></span><br><span class="line"><span class="comment">// 1. 获取并启动监听器</span></span><br><span class="line"><span class="type">SpringApplicationRunListeners</span> <span class="variable">listeners</span> <span class="operator">=</span> getRunListeners(args);</span><br><span class="line"><span class="comment">// 启动监听器</span></span><br><span class="line">listeners.starting();</span><br><span class="line"></span><br><span class="line"><span class="comment">//① getRunListeners()方法</span></span><br><span class="line"><span class="keyword">private</span> SpringApplicationRunListeners <span class="title function_">getRunListeners</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">		Class&lt;?&gt;[] types = <span class="keyword">new</span> <span class="title class_">Class</span>&lt;?&gt;[]&#123;SpringApplication.class, String[].class&#125;;</span><br><span class="line">		<span class="comment">// SpringApplicationRunListeners负责在springboot启动的不同阶段广播出不同的消息，传递给ApplicationListener监听器实现类</span></span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">SpringApplicationRunListeners</span>(logger,</span><br><span class="line">				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, <span class="built_in">this</span>, args));</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ② getSpringFactoriesInstances()方法</span></span><br><span class="line"><span class="keyword">private</span> &lt;T&gt; Collection&lt;T&gt; <span class="title function_">getSpringFactoriesInstances</span><span class="params">(Class&lt;T&gt; type, Class&lt;?&gt;[] parameterTypes, Object... args)</span> &#123;</span><br><span class="line">		<span class="type">ClassLoader</span> <span class="variable">classLoader</span> <span class="operator">=</span> getClassLoader();</span><br><span class="line">		<span class="comment">// Use names and ensure unique to protect against duplicates</span></span><br><span class="line">		<span class="comment">// 通过指定的classLoader从 META-INF/spring.properties的资源文件中读取key为type.getName()的value值</span></span><br><span class="line">		Set&lt;String&gt; names = <span class="keyword">new</span> <span class="title class_">LinkedHashSet</span>&lt;&gt;(SpringFactoriesLoader.loadFactoryNames(type, classLoader));</span><br><span class="line">		<span class="comment">// 创建spring工厂实例</span></span><br><span class="line">		List&lt;T&gt; instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);</span><br><span class="line">		<span class="comment">// 对spring工厂实例进行排序（org.springframework.core.annotation.Order注解指定的顺序）</span></span><br><span class="line">		AnnotationAwareOrderComparator.sort(instances);</span><br><span class="line">		<span class="keyword">return</span> instances;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="4-2-2-构造应用上下文环境"><a href="#4-2-2-构造应用上下文环境" class="headerlink" title="4.2.2 构造应用上下文环境"></a>4.2.2 构造应用上下文环境</h5><p>调用方法 prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) 构造应用上下文环境，具体流程如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> ConfigurableEnvironment <span class="title function_">prepareEnvironment</span><span class="params">(SpringApplicationRunListeners listeners,</span></span><br><span class="line"><span class="params">													   ApplicationArguments applicationArguments)</span> &#123;</span><br><span class="line">		<span class="comment">// 1. Create and configure the environment 创建并配置相应的环境</span></span><br><span class="line">		<span class="type">ConfigurableEnvironment</span> <span class="variable">environment</span> <span class="operator">=</span> getOrCreateEnvironment();</span><br><span class="line">		<span class="comment">// 2. 根据用户配置，配置environment系统环境</span></span><br><span class="line">		configureEnvironment(environment, applicationArguments.getSourceArgs());</span><br><span class="line">		ConfigurationPropertySources.attach(environment);</span><br><span class="line">		<span class="comment">// 3. 启动相应的监听器，其中一个重要的监听器 ConfigFileApplicationListener 就是加载项目配置文件的监听器</span></span><br><span class="line">		listeners.environmentPrepared(environment);</span><br><span class="line">		bindToSpringApplication(environment);</span><br><span class="line">		<span class="keyword">if</span> (!<span class="built_in">this</span>.isCustomEnvironment) &#123;</span><br><span class="line">			environment = <span class="keyword">new</span> 			<span class="title class_">EnvironmentConverter</span>(getClassLoader()).convertEnvironmentIfNecessary(environment,</span><br><span class="line">					deduceEnvironmentClass());</span><br><span class="line">		&#125;</span><br><span class="line">		ConfigurationPropertySources.attach(environment);</span><br><span class="line">    	<span class="comment">// 将相关信息加载完成并封装到environment对象中进行返回</span></span><br><span class="line">		<span class="keyword">return</span> environment;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*********************************************以下方法被上述方法调用******************************************/</span></span><br><span class="line">① 创建并配置相应的环境</span><br><span class="line">    <span class="keyword">private</span> ConfigurableEnvironment <span class="title function_">getOrCreateEnvironment</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.environment != <span class="literal">null</span>) &#123;</span><br><span class="line">			<span class="keyword">return</span> <span class="built_in">this</span>.environment;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 判断应用类型，如果是Servlet则实例化StandardServletEnvironment</span></span><br><span class="line">		<span class="keyword">switch</span> (<span class="built_in">this</span>.webApplicationType) &#123;</span><br><span class="line">			<span class="keyword">case</span> SERVLET:</span><br><span class="line">				<span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">StandardServletEnvironment</span>();</span><br><span class="line">			<span class="keyword">case</span> REACTIVE:</span><br><span class="line">				<span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">StandardReactiveWebEnvironment</span>();</span><br><span class="line">			<span class="keyword">default</span>:</span><br><span class="line">				<span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">StandardEnvironment</span>();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">②  根据用户配置，配置environment系统环境（java_home、maven_home、jdk等相关系统信息）</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configureEnvironment</span><span class="params">(ConfigurableEnvironment environment, String[] args)</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.addConversionService) &#123;</span><br><span class="line">			<span class="type">ConversionService</span> <span class="variable">conversionService</span> <span class="operator">=</span> ApplicationConversionService.getSharedInstance();</span><br><span class="line">			environment.setConversionService((ConfigurableConversionService) conversionService);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 将main方法的 args 参数封装成SimpleCommandLinePropertySource 加入到环境中</span></span><br><span class="line">		configurePropertySources(environment, args);</span><br><span class="line">		<span class="comment">// 激活相应的配置文件</span></span><br><span class="line">		configureProfiles(environment, args);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configurePropertySources</span><span class="params">(ConfigurableEnvironment environment, String[] args)</span> &#123;</span><br><span class="line">		<span class="type">MutablePropertySources</span> <span class="variable">sources</span> <span class="operator">=</span> environment.getPropertySources();</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.defaultProperties != <span class="literal">null</span> &amp;&amp; !<span class="built_in">this</span>.defaultProperties.isEmpty()) &#123;</span><br><span class="line">			sources.addLast(<span class="keyword">new</span> <span class="title class_">MapPropertySource</span>(<span class="string">&quot;defaultProperties&quot;</span>, <span class="built_in">this</span>.defaultProperties));</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.addCommandLineProperties &amp;&amp; args.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">			<span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;</span><br><span class="line">			<span class="keyword">if</span> (sources.contains(name)) &#123;</span><br><span class="line">				PropertySource&lt;?&gt; source = sources.get(name);</span><br><span class="line">				<span class="type">CompositePropertySource</span> <span class="variable">composite</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CompositePropertySource</span>(name);</span><br><span class="line">				composite.addPropertySource(</span><br><span class="line">						<span class="keyword">new</span> <span class="title class_">SimpleCommandLinePropertySource</span>(<span class="string">&quot;springApplicationCommandLineArgs&quot;</span>, args));</span><br><span class="line">				composite.addPropertySource(source);</span><br><span class="line">				sources.replace(name, composite);</span><br><span class="line">			&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">				sources.addFirst(<span class="keyword">new</span> <span class="title class_">SimpleCommandLinePropertySource</span>(args));</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configureProfiles</span><span class="params">(ConfigurableEnvironment environment, String[] args)</span> &#123;</span><br><span class="line">		Set&lt;String&gt; profiles = <span class="keyword">new</span> <span class="title class_">LinkedHashSet</span>&lt;&gt;(<span class="built_in">this</span>.additionalProfiles);</span><br><span class="line">		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));</span><br><span class="line">		environment.setActiveProfiles(StringUtils.toStringArray(profiles));</span><br><span class="line">	&#125;</span><br><span class="line">③ 通过 ConfigFileApplicationListener 监听器 完成配置文件的加载</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@link</span> EnvironmentPostProcessor&#125; that configures the context environment by loading</span></span><br><span class="line"><span class="comment"> * properties from well known file locations. By default properties will be loaded from</span></span><br><span class="line"><span class="comment"> * &#x27;application.properties&#x27; and/or &#x27;application.yml&#x27; filesin the following locations:</span></span><br><span class="line"><span class="comment"> * &lt;ul&gt; 该监听器会从以下四个位置加载 &#x27;application.properties&#x27; and/or &#x27;application.yml&#x27; files 类型配置文件</span></span><br><span class="line"><span class="comment"> * &lt;li&gt;file:./config/&lt;/li&gt;</span></span><br><span class="line"><span class="comment"> * &lt;li&gt;file:./&lt;/li&gt;</span></span><br><span class="line"><span class="comment"> * &lt;li&gt;classpath:config/&lt;/li&gt;</span></span><br><span class="line"><span class="comment"> * &lt;li&gt;classpath:&lt;/li&gt;</span></span><br><span class="line"><span class="comment"> * &lt;/ul&gt;</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>

<h5 id="4-2-3-初始化应用上下文"><a href="#4-2-3-初始化应用上下文" class="headerlink" title="4.2.3 初始化应用上下文"></a>4.2.3 初始化应用上下文</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">protected ConfigurableApplicationContext createApplicationContext() &#123;</span><br><span class="line">		Class&lt;?&gt; contextClass = this.applicationContextClass;</span><br><span class="line">		if (contextClass == null) &#123;</span><br><span class="line">			try &#123;</span><br><span class="line">				switch (this.webApplicationType) &#123;</span><br><span class="line">					case SERVLET:</span><br><span class="line">					//DEFAULT_SERVLET_WEB_CONTEXT_CLASS对应类：org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext</span><br><span class="line"></span><br><span class="line">						contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);</span><br><span class="line">						break;</span><br><span class="line">					case REACTIVE:</span><br><span class="line">						contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);</span><br><span class="line">						break;</span><br><span class="line">					default:</span><br><span class="line">						contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);</span><br><span class="line">				&#125;</span><br><span class="line">			&#125; catch (ClassNotFoundException ex) &#123;</span><br><span class="line">				throw new IllegalStateException(</span><br><span class="line">						&quot;Unable create a default ApplicationContext, please specify an ApplicationContextClass&quot;, ex);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>

<p>通过BeanUtils.instantiateClass(contextClass)方法初始化应用上下文，应用上下文初始化的同时也创建了IOC容器（存于context上下文中的beanFactory，对应的值是DefaultListableBeanFactory）</p>
<h5 id="4-2-4-刷新应用上下文前的准备阶段"><a href="#4-2-4-刷新应用上下文前的准备阶段" class="headerlink" title="4.2.4 刷新应用上下文前的准备阶段"></a>4.2.4 <em>刷新应用上下文前的准备阶段</em></h5><p>该过程完成context上下文中属性值的设置，以及bean对象的创建：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">prepareContext</span><span class="params">(ConfigurableApplicationContext context, ConfigurableEnvironment environment,</span></span><br><span class="line"><span class="params">								SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner)</span> &#123;</span><br><span class="line">		<span class="comment">//1. 设置容器环境，将第二步构建出来的上下文对象设置到context上下文中</span></span><br><span class="line">		context.setEnvironment(environment);</span><br><span class="line">		<span class="comment">//2. 执行容器后置处理(也是向context上下文中设置值)</span></span><br><span class="line">		postProcessApplicationContext(context);</span><br><span class="line">		<span class="comment">//3. 启动SpringBootApplication初始化过程中加载的初始化器</span></span><br><span class="line">		applyInitializers(context);</span><br><span class="line">		<span class="comment">/**以下代码完成bean对象的创建*/</span></span><br><span class="line">		<span class="comment">//4.1 向各个监听器发送容器已经准备好的事件</span></span><br><span class="line">		listeners.contextPrepared(context);</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.logStartupInfo) &#123;</span><br><span class="line">			logStartupInfo(context.getParent() == <span class="literal">null</span>);</span><br><span class="line">			logStartupProfileInfo(context);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// Add boot specific singleton beans</span></span><br><span class="line">		<span class="type">ConfigurableListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getBeanFactory();</span><br><span class="line">		<span class="comment">//4.2 将main()方法中的args参数封装成单例Bean，注册进容器</span></span><br><span class="line">		beanFactory.registerSingleton(<span class="string">&quot;springApplicationArguments&quot;</span>, applicationArguments);</span><br><span class="line">		<span class="keyword">if</span> (printedBanner != <span class="literal">null</span>) &#123;</span><br><span class="line">			<span class="comment">//4.3 将printedBanner也封装成单例，注册进容器</span></span><br><span class="line">			beanFactory.registerSingleton(<span class="string">&quot;springBootBanner&quot;</span>, printedBanner);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (beanFactory <span class="keyword">instanceof</span> DefaultListableBeanFactory) &#123;</span><br><span class="line">			((DefaultListableBeanFactory) beanFactory)</span><br><span class="line">					.setAllowBeanDefinitionOverriding(<span class="built_in">this</span>.allowBeanDefinitionOverriding);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.lazyInitialization) &#123;</span><br><span class="line">			context.addBeanFactoryPostProcessor(<span class="keyword">new</span> <span class="title class_">LazyInitializationBeanFactoryPostProcessor</span>());</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 4.4 Load the sources  加载启动类</span></span><br><span class="line">		Set&lt;Object&gt; sources = getAllSources();</span><br><span class="line">		Assert.notEmpty(sources, <span class="string">&quot;Sources must not be empty&quot;</span>);</span><br><span class="line">		<span class="comment">//4.5 加载启动类，将启动类注入容器</span></span><br><span class="line">		load(context, sources.toArray(<span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]));</span><br><span class="line">		<span class="comment">//4.6 发布容器已加载事件</span></span><br><span class="line">		listeners.contextLoaded(context);</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>

<p>note：spring容器在启动过程中，会将类解析成spring内部的beanDefinition结构，并将beanDefinition存储到DefaultListableBeanFactory的map中（即context上下文的beanFactory（DefaultListableBeanFactory类型）的beanDefinitionMap）</p>
<h5 id="4-2-5-刷新应用上下文"><a href="#4-2-5-刷新应用上下文" class="headerlink" title="4.2.5 刷新应用上下文"></a>4.2.5 <em>刷新应用上下文</em></h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 5. 刷新应用上下文</span></span><br><span class="line">refreshContext(context);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/****以下方法被上述方法调用****/</span></span><br><span class="line">	<span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">refreshContext</span><span class="params">(ConfigurableApplicationContext context)</span> &#123;</span><br><span class="line">		refresh(context);</span><br><span class="line">		<span class="keyword">if</span> (<span class="built_in">this</span>.registerShutdownHook) &#123;</span><br><span class="line">			<span class="keyword">try</span> &#123;</span><br><span class="line">				context.registerShutdownHook();</span><br><span class="line">			&#125; <span class="keyword">catch</span> (AccessControlException ex) &#123;</span><br><span class="line">				<span class="comment">// Not allowed in some environments.</span></span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">refresh</span><span class="params">(ApplicationContext applicationContext)</span> &#123;</span><br><span class="line">		<span class="comment">// 将applicationContext进行类型转化</span></span><br><span class="line">		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);</span><br><span class="line">		((AbstractApplicationContext) applicationContext).refresh();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/*********通过以下spring源码，完成应用上下文的刷新**********/</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">refresh</span><span class="params">()</span> <span class="keyword">throws</span> BeansException, IllegalStateException &#123;</span><br><span class="line">        <span class="keyword">synchronized</span>(<span class="built_in">this</span>.startupShutdownMonitor) &#123;</span><br><span class="line">            <span class="built_in">this</span>.prepareRefresh();</span><br><span class="line">            <span class="type">ConfigurableListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="built_in">this</span>.obtainFreshBeanFactory();</span><br><span class="line">            <span class="built_in">this</span>.prepareBeanFactory(beanFactory);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="built_in">this</span>.postProcessBeanFactory(beanFactory);</span><br><span class="line">                <span class="comment">// </span></span><br><span class="line">                <span class="built_in">this</span>.invokeBeanFactoryPostProcessors(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.registerBeanPostProcessors(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.initMessageSource();</span><br><span class="line">                <span class="built_in">this</span>.initApplicationEventMulticaster();</span><br><span class="line">                <span class="comment">// 这里会调用6.1中的 getWebServer()方法，完成Tomcat容器的创建及启动</span></span><br><span class="line">                <span class="built_in">this</span>.onRefresh();</span><br><span class="line">                <span class="built_in">this</span>.registerListeners();</span><br><span class="line">                <span class="built_in">this</span>.finishBeanFactoryInitialization(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.finishRefresh();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (BeansException var9) &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isWarnEnabled()) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.logger.warn(<span class="string">&quot;Exception encountered during context initialization - cancelling refresh attempt: &quot;</span> + var9);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="built_in">this</span>.destroyBeans();</span><br><span class="line">                <span class="built_in">this</span>.cancelRefresh(var9);</span><br><span class="line">                <span class="keyword">throw</span> var9;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="built_in">this</span>.resetCommonCaches();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">			</span><br></pre></td></tr></table></figure>

<ol>
<li><p>invokeBeanFactoryPostProcessors(beanFactory)</p>
<p>IOC容器初始化过程包括三个步骤，在invokeBeanFactoryPostProcessors()方法中完成了IOC容器初始化过程的三个步骤。</p>
<ol>
<li>Resource定位</li>
<li>BeanDefinition的载入</li>
<li>注册BeanDefinition</li>
</ol>
</li>
</ol>
<h5 id="4-2-6-刷新应用上下文后的扩展接口"><a href="#4-2-6-刷新应用上下文后的扩展接口" class="headerlink" title="4.2.6 刷新应用上下文后的扩展接口"></a>4.2.6 刷新应用上下文后的扩展接口</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 6. 刷新应用上下文后的扩展接口</span></span><br><span class="line">afterRefresh(context, applicationArguments);</span><br></pre></td></tr></table></figure>

<p>这里使用了设计模式中的‘模板方法模式’，afterRefresh()该方法内部为空实现（方法中没有任何代码），当有一些自定义需求如：启动结束后打印一些log，或一些其他的后续处理，可以重写该方法实现扩展接口，进而完成自定义需求</p>
<h3 id="5-自定义Starter"><a href="#5-自定义Starter" class="headerlink" title="5.自定义Starter"></a>5.自定义Starter</h3><h4 id="5-1-自定义start的命名规则"><a href="#5-1-自定义start的命名规则" class="headerlink" title="5.1 自定义start的命名规则"></a>5.1 自定义start的命名规则</h4><p>SpringBoot提供的starter以 spring-boot-starter-xxx 的方式命名，官方建议自定义的starter使用 xxx-spring-boot-starter 的命名规则，以区分SpringBoot生态提供的starter.(Starter 就是一个外部的Springboot项目)</p>
<h4 id="5-2-自定义starter代码实现"><a href="#5-2-自定义starter代码实现" class="headerlink" title="5.2 自定义starter代码实现"></a>5.2 自定义starter代码实现</h4><ol>
<li><p>新建maven jar 工程，命名方式为 xxx-spring-boot-starter，导入依赖</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!--自动配置核心依赖--&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">	&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">	&lt;artifactId&gt;spring-boot-autoconfigure&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure>

<p>该依赖为完成自动配置所需的核心依赖</p>
</li>
<li><p>编写JavaBean（工程所需要的通用实体类）</p>
<ol>
<li>添加注解@Configuration</li>
<li>注解@EnableConfigurationProperties(BeanName.class)</li>
<li>注解@ConfigurationProperties(prefix=“xxx”)使用该注解实现配置文件中配置该bean内的属性值</li>
</ol>
</li>
<li><p>编写一个自动配置类MyAutoConfiguration</p>
</li>
<li><p>resources下创建目录 ：/META-INF/spring.factories</p>
<ol>
<li><p>注意：META-INF是自己手动创建的目录，spring.factories也是手动创建的文件，在该文件中配置自己的自动配置类(这一种变形的SPI机制)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 示例 通过配置spring.factories文件，实现自定义的配置类的自动装配</span><br><span class="line">org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xpffly.config.MyConfiguration</span><br></pre></td></tr></table></figure></li>
</ol>
</li>
<li></li>
</ol>
<h4 id="5-3-热插拔技术"><a href="#5-3-热插拔技术" class="headerlink" title="5.3 热插拔技术"></a>5.3 热插拔技术</h4><p>​    通过自定义注解实现热插拔技术。</p>
<p>在上述的MyAutoConfiguration类上通过@ConditionalOnBean(xxx.class)实现热插拔技术（即自定义配置类上标明，上下文中必须有自定义的注解时才生效）</p>
<p><img src="D:\software\Typora\Typora文件\图片\image-20210803210956924.png" alt="image-20210803210956924"></p>
<h3 id="6-内嵌Tomcat原理"><a href="#6-内嵌Tomcat原理" class="headerlink" title="6.内嵌Tomcat原理"></a>6.内嵌Tomcat原理</h3><p>spring-boot-autoconfigure自动配置模块的spring.factories中自动配置key=“org.springframework.boot.autoconfigure.EnableAutoConfiguration”对应的value中有“org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration”即为Tomcat的自动配置类</p>
<h4 id="6-1-内嵌Tomcat启动原理"><a href="#6-1-内嵌Tomcat启动原理" class="headerlink" title="6.1 内嵌Tomcat启动原理"></a>6.1 内嵌Tomcat启动原理</h4><ol>
<li><p>ServletWebServerFactoryAutoConfiguration 自动配置类中通过 @Import 注解 引入了 组件：ServletWebServerFactoryConfiguration.EmbeddedTomcat.class</p>
</li>
<li><p>在类ServletWebServerFactoryConfiguration中通过静态代码生成了 创建Tomcat的工厂</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">@Configuration(proxyBeanMethods = false)</span><br><span class="line">@ConditionalOnClass(&#123; Servlet.class, Tomcat.class, UpgradeProtocol.class &#125;)</span><br><span class="line">@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)</span><br><span class="line">static class EmbeddedTomcat &#123;</span><br><span class="line">	/**</span><br><span class="line">	 * 创建生成 Tomcat 的工厂</span><br><span class="line">	 * @param connectorCustomizers</span><br><span class="line">	 * @param contextCustomizers</span><br><span class="line">	 * @param protocolHandlerCustomizers</span><br><span class="line">	 * @return</span><br><span class="line">	 */</span><br><span class="line">	@Bean</span><br><span class="line">	TomcatServletWebServerFactory tomcatServletWebServerFactory(</span><br><span class="line">			ObjectProvider&lt;TomcatConnectorCustomizer&gt; connectorCustomizers,</span><br><span class="line">			ObjectProvider&lt;TomcatContextCustomizer&gt; contextCustomizers,</span><br><span class="line">			ObjectProvider&lt;TomcatProtocolHandlerCustomizer&lt;?&gt;&gt; protocolHandlerCustomizers) &#123;</span><br><span class="line">		// 创建工厂对象并设置其属性值</span><br><span class="line">		TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();</span><br><span class="line">		factory.getTomcatConnectorCustomizers()</span><br><span class="line">				.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">		factory.getTomcatContextCustomizers()</span><br><span class="line">				.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">		factory.getTomcatProtocolHandlerCustomizers()</span><br><span class="line">				.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));</span><br><span class="line">		return factory;</span><br><span class="line">	&#125;</span><br><span class="line">   </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>通过 new TomcatServletWebServerFactory()  创建工厂对象，TomcatServletWebServerFactory类中有public WebServer getWebServer(ServletContextInitializer… initializers)方法，通过该方法完成Tomcat的创建以及启动柜</p>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 创建并启动内嵌的 tomcat</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> initializers &#123;<span class="doctag">@link</span> ServletContextInitializer&#125;s that should be applied as</span></span><br><span class="line"><span class="comment"> * the server starts</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> WebServer <span class="title function_">getWebServer</span><span class="params">(ServletContextInitializer... initializers)</span> &#123;</span><br><span class="line">	<span class="keyword">if</span> (<span class="built_in">this</span>.disableMBeanRegistry) &#123;</span><br><span class="line">		Registry.disableRegistry();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 1. 实例化一个 Tomcat 对象</span></span><br><span class="line">	<span class="type">Tomcat</span> <span class="variable">tomcat</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tomcat</span>();</span><br><span class="line">	<span class="type">File</span> <span class="variable">baseDir</span> <span class="operator">=</span> (<span class="built_in">this</span>.baseDirectory != <span class="literal">null</span>) ? <span class="built_in">this</span>.baseDirectory : createTempDir(<span class="string">&quot;tomcat&quot;</span>);</span><br><span class="line">	<span class="comment">// 2. 设置Tomcat的临时工作目录</span></span><br><span class="line">	tomcat.setBaseDir(baseDir.getAbsolutePath());</span><br><span class="line">	<span class="comment">// 3. 默认使用 org.apache.coyote.http11.Http11NioProtocol 实例化 Connector</span></span><br><span class="line">	<span class="type">Connector</span> <span class="variable">connector</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Connector</span>(<span class="built_in">this</span>.protocol);</span><br><span class="line">	connector.setThrowOnFailure(<span class="literal">true</span>);</span><br><span class="line">	<span class="comment">// 4. 给 service 添加 Connector</span></span><br><span class="line">	tomcat.getService().addConnector(connector);</span><br><span class="line">	customizeConnector(connector);</span><br><span class="line">	tomcat.setConnector(connector);</span><br><span class="line">	<span class="comment">// 5. 关闭热部署</span></span><br><span class="line">	tomcat.getHost().setAutoDeploy(<span class="literal">false</span>);</span><br><span class="line">	<span class="comment">// 6. 配置 engine</span></span><br><span class="line">	configureEngine(tomcat.getEngine());</span><br><span class="line">	<span class="keyword">for</span> (Connector additionalConnector : <span class="built_in">this</span>.additionalTomcatConnectors) &#123;</span><br><span class="line">		tomcat.getService().addConnector(additionalConnector);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// 7. 实例化 TomcatWebServer 时，会将DispatcherServlet以及一些Filter添加到Tomcat中</span></span><br><span class="line">	prepareContext(tomcat.getHost(), initializers);</span><br><span class="line">	<span class="keyword">return</span> getTomcatWebServer(tomcat);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h4 id="6-2"><a href="#6-2" class="headerlink" title="6.2"></a>6.2</h4><h3 id="7"><a href="#7" class="headerlink" title="7."></a>7.</h3>
    </div>
    
    <div class="post-footer">
        <div>
            
            转载声明：
            商业转载请联系作者获得授权,非商业转载请注明出处.
            
            
        </div>
        <div>
            
        </div>
    </div>
</article>
<div class="article-nav prev-next-wrap clearfix">
    
    <a href="/2022/04/10/%E6%B5%8B%E8%AF%95%E5%91%80/" class="pre-post btn btn-default" title='测试呀'>
        <i class="fa fa-angle-left fa-fw"></i><span class="hidden-lg">上一篇</span>
        <span class="hidden-xs">
            测试呀</span>
    </a>
    
    
    <a href="/2022/04/05/hello-world/" class="next-post btn btn-default" title='Hello World'>
        <span class="hidden-lg">下一篇</span>
        <span class="hidden-xs">
            Hello World</span><i class="fa fa-angle-right fa-fw"></i>
    </a>
    
</div>

<div id="comments">
    
    
<div id="vcomments" class="valine"></div>

<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="/assets/valine.min.js"></script>

<script>
    new Valine({
        av: AV,
        el: '#vcomments',
        appId: 'xOKV9J4UeQAtVkvnJC7Kq2Jn-gzGzoHsz',
        appKey: 'erIpQac4azoCmgfBB7Dl9maa',
        placeholder: '说点什么吧',
        notify: false,
        verify: false,
        avatar: 'mm',
        meta: 'nick,mail'.split(','),
        pageSize: '10',
        path: window.location.pathname,
        lang: 'zh-CN'.toLowerCase()
    })
    </script>


</div>

                </main>
                
                    <aside id="article-toc" role="navigation" class="col-md-4">
    <div class="widget">
        <h3 class="title">
            文章目录
        </h3>
        
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Springboot%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90"><span class="toc-text">Springboot源码剖析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA"><span class="toc-text">1.环境搭建</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-%E4%B8%8B%E8%BD%BD%E6%BA%90%E7%A0%81"><span class="toc-text">1.1 下载源码</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-%E7%BC%96%E8%AF%91%E6%BA%90%E7%A0%81"><span class="toc-text">1.2 编译源码</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-%E6%96%B0%E5%BB%BAmodule"><span class="toc-text">1.3  新建module</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-%E9%AA%8C%E8%AF%81"><span class="toc-text">1.4 验证</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86"><span class="toc-text">2.依赖管理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-SpringBoot-Start"><span class="toc-text">2.1 SpringBoot Start</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-spring-boot-start-parent"><span class="toc-text">2.2 spring-boot-start-parent</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-spring-boot-start-web"><span class="toc-text">2.3 spring-boot-start-web</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="toc-text">3.自动配置</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-%E5%85%83%E6%B3%A8%E8%A7%A3"><span class="toc-text">3.1 元注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-SpringBootApplication"><span class="toc-text">3.2 @SpringBootApplication</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E6%80%BB%E7%BB%93"><span class="toc-text">3.3 自动配置原理总结</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-run%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-text">4.run方法执行流程</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-SpringBootApplication-%E5%88%9D%E5%A7%8B%E5%8C%96%E8%BF%87%E7%A8%8B"><span class="toc-text">4.1 SpringBootApplication  初始化过程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-run%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-text">4.2 run方法执行流程</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#4-2-1-%E8%8E%B7%E5%8F%96%E5%90%AF%E5%8A%A8%E7%9B%91%E5%90%AC%E5%99%A8"><span class="toc-text">4.2.1 获取启动监听器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-2-2-%E6%9E%84%E9%80%A0%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E7%8E%AF%E5%A2%83"><span class="toc-text">4.2.2 构造应用上下文环境</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-2-3-%E5%88%9D%E5%A7%8B%E5%8C%96%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87"><span class="toc-text">4.2.3 初始化应用上下文</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-2-4-%E5%88%B7%E6%96%B0%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87%E9%98%B6%E6%AE%B5"><span class="toc-text">4.2.4 刷新应用上下文前的准备阶段</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-2-5-%E5%88%B7%E6%96%B0%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87"><span class="toc-text">4.2.5 刷新应用上下文</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-2-6-%E5%88%B7%E6%96%B0%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E5%90%8E%E7%9A%84%E6%89%A9%E5%B1%95%E6%8E%A5%E5%8F%A3"><span class="toc-text">4.2.6 刷新应用上下文后的扩展接口</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-%E8%87%AA%E5%AE%9A%E4%B9%89Starter"><span class="toc-text">5.自定义Starter</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-%E8%87%AA%E5%AE%9A%E4%B9%89start%E7%9A%84%E5%91%BD%E5%90%8D%E8%A7%84%E5%88%99"><span class="toc-text">5.1 自定义start的命名规则</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-%E8%87%AA%E5%AE%9A%E4%B9%89starter%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0"><span class="toc-text">5.2 自定义starter代码实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-3-%E7%83%AD%E6%8F%92%E6%8B%94%E6%8A%80%E6%9C%AF"><span class="toc-text">5.3 热插拔技术</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-%E5%86%85%E5%B5%8CTomcat%E5%8E%9F%E7%90%86"><span class="toc-text">6.内嵌Tomcat原理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-1-%E5%86%85%E5%B5%8CTomcat%E5%90%AF%E5%8A%A8%E5%8E%9F%E7%90%86"><span class="toc-text">6.1 内嵌Tomcat启动原理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2"><span class="toc-text">6.2</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7"><span class="toc-text">7.</span></a></li></ol></li></ol>
        
    </div>
</aside>
                
            </div>
        </div>
    </section>
    <footer class="main-footer">
    <div class="container">
        <div class="row">
        </div>
    </div>
</footer>
<a id="back-to-top" class="icon-btn hide">
    <i class="fa fa-chevron-up"></i>
</a>
    <div class="copyright">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="busuanzi">
    
</div>
            </div>
            <div class="col-sm-12">
                <span>Copyright &copy;
                    2022
                    
                </span> |
                <span>
                    Powered by 也邢
                </span>
            </div>
        </div>
    </div>
</div>




<script src="/js/app.js?rev=@@hash.js"></script>

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"model":{"jsonPath":"/live2dw/assets/koharu.model.json"},"display":{"position":"left","width":150,"height":300},"mobile":{"show":false},"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>